package com.moliku.insurance.process.service.impl;

import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.moliku.insurance.common.constant.CompanyEnum;
import com.moliku.insurance.common.constant.InsureStatusEnum;
import com.moliku.insurance.common.constant.OrderEnum;
import com.moliku.insurance.common.constant.PolicyConfigKeyEnum;
import com.moliku.insurance.common.response.CommonInsureResult;
import com.moliku.insurance.common.response.ResponseCode;
import com.moliku.insurance.model.dto.CancelInsureDTO;
import com.moliku.insurance.model.dto.DownloadInsureDTO;
import com.moliku.insurance.model.dto.insure.InsureDTO;
import com.moliku.insurance.model.dto.insure.InsuredInfoDTO;
import com.moliku.insurance.model.entity.Order;
import com.moliku.insurance.model.entity.OrderDetail;
import com.moliku.insurance.model.entity.starr.StarrInsured;
import com.moliku.insurance.model.entity.starr.StarrSubmitPolicy;
import com.moliku.insurance.process.mapper.BaseOrderMapper;
import com.moliku.insurance.process.service.ConfigService;
import com.moliku.insurance.process.strategy.PolicyStrategy;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 史带中国
 *
 * @author Mr.Liu
 * @since 2021/2/25
 */
@Slf4j
@AllArgsConstructor
@Service("StarrService")
public class StarrServiceImpl implements PolicyStrategy {
    /**
     * 创建会话URL
     */
//    private static final String CREATE_SESSION_URL = "http://dicc2.ins24.com/ah/session";
    /**
     * 投保、退保URL
     */
//    private static final String SUBMIT_POLICY_URL = "http://dicc2.ins24.com/ah/policies";
    /**
     * 下载保单URL
     */
//    private static final String DOWNLOAD_POLICY_URL = "http://dicc2.ins24.com/ah/pdf_printer/policies";

    /**
     * 投保成功的状态码
     */
    private static final String INSURED_SUCCESS_CODE = "1301";
    /**
     * 登录成功的状态码
     */
    private static final String LOGIN_SUCCESS_CODE = "1508";
    /**
     * 退保成功的状态码
     */
    private static final String CANCEL_SUCCESS_CODE = "1302";

    private final RestTemplate restTemplate;
    @Autowired
    private BaseOrderMapper baseOrderMapper;
    @Autowired
    private ConfigService configService;

    @Override
    public CommonInsureResult submitPolicy(InsureDTO data) {

        try {
            //保单主体信息
            StarrSubmitPolicy starrSubmitPolicy = new StarrSubmitPolicy();
            starrSubmitPolicy.setPHName(data.getPolicyHolder().getcName());
            starrSubmitPolicy.setPHMail(data.getPolicyHolder().getEmail());
            starrSubmitPolicy.setPHTel(data.getPolicyHolder().getMobile());
            starrSubmitPolicy.setPHBirth(data.getPolicyHolder().getBirthDay());
            starrSubmitPolicy.setPHIdNoType(getCardType(data.getPolicyHolder().getCardType()));
            starrSubmitPolicy.setPHIdNo(data.getPolicyHolder().getCardNo());
            starrSubmitPolicy.setPlanID(data.getOrder().getProductCode());
            starrSubmitPolicy.setDateStart(data.getOrder().getStartTime());
            starrSubmitPolicy.setDateEnd(data.getOrder().getEndTime());
            starrSubmitPolicy.setSerialNo(data.getOrder().getSerialNumber());
            List<StarrInsured> starrInsuredList = new ArrayList<StarrInsured>();
            //被保人信息
            for (InsuredInfoDTO infoDTO : data.getInsureds()) {
                StarrInsured starrInsured = new StarrInsured();
                starrInsured.setName(infoDTO.getCName());
                starrInsured.setIdNoType(getCardType(infoDTO.getCardType()));
                starrInsured.setIdNo(infoDTO.getCardNo());
                starrInsured.setBirthDt(infoDTO.getBirthDay());
                starrInsured.setTel(infoDTO.getMobile());
                starrInsured.setSex(infoDTO.getSex());
                starrInsured.setMail(infoDTO.getEmail());
                starrInsuredList.add(starrInsured);
            }
            starrSubmitPolicy.setInsured(starrInsuredList);
            log.info("请求报文：{}", JSONUtil.parseObj(starrSubmitPolicy).toString());

            //建立会话获取cookie
            Map<String, Object> map = getCookie();
            JSONObject json = JSONUtil.parseObj(map.get("body"));
            if (!LOGIN_SUCCESS_CODE.equals(String.valueOf(json.get("code")))) {
                log.error("登录史带接口时参数错误");
                return CommonInsureResult.submitPolicyFail("史带保险建立会话接口错误");
            }
            //发起投保请求
            HttpHeaders headers = new HttpHeaders();
            List<String> cookie = new ArrayList<String>();
            cookie.add(map.get("cookie").toString());
            headers.put(HttpHeaders.COOKIE, cookie);
            headers.add(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
            JSONObject object = JSONUtil.parseObj(starrSubmitPolicy);
            HttpEntity<String> request = new HttpEntity<String>(object.toString(), headers);
            //查询投保地址
            String submitPolicyUrl = configService.getConfigValue(CompanyEnum.STARR, PolicyConfigKeyEnum.SUBMIT_POLICY_URL);
            ResponseEntity<String> subResponse = restTemplate.postForEntity(submitPolicyUrl, request, String.class);
            JSONObject responseJson = JSONUtil.parseObj(subResponse.getBody());
            log.info("投保请求返回：{}", subResponse.getBody());
            //保存返回结果
            Order order = baseOrderMapper.selectById(data.getLocalOrderId());
            OrderDetail orderDetail = baseOrderMapper.selectDeatailByOrderId(order.getId());
            orderDetail.setInsureRsp(subResponse.getBody());
            baseOrderMapper.updateOrderDeatailByOrderId(orderDetail);
            Object policyNumber = new Object();
            InsureStatusEnum message;
            //文档中：只有返回code值为1301时投保才成功
            if (INSURED_SUCCESS_CODE.equals(String.valueOf(responseJson.get("code")))) {
                JSONArray jsonArray = JSONUtil.parseArray(responseJson.get("PolicyNumber"));
                policyNumber = jsonArray.get(0);
                message = returnMes(String.valueOf(responseJson.get("code")));
                //修改数据库保单状态
                order.setPolicyNo(String.valueOf(policyNumber));
                order.setStatus(OrderEnum.CLOSED_NO_REFUND.getValue());
                baseOrderMapper.updateById(order);
            } else {
                message = returnMes(String.valueOf(responseJson.get("code")));
            }
            //查询会话URL
            String createSessionUrl = configService.getConfigValue(CompanyEnum.STARR, "createSessionUrl");
            //关闭会话
            ResponseEntity<String> userDelete = restTemplate.exchange(createSessionUrl, HttpMethod.DELETE, null, String.class);
            log.info("关闭会话返回：{}", userDelete.getBody());
            if (null == policyNumber) {
                return CommonInsureResult.submitPolicyFail(String.valueOf(policyNumber));
            }
            if (InsureStatusEnum.INSURE_SUCCESS.equals(message)) {
                return CommonInsureResult.submitPolicySuccess(String.valueOf(policyNumber));
            }
            if (message.getCode() == 5400) {
                String res = UnicodeUtil.toString(String.valueOf(responseJson.get("msg")));
                return CommonInsureResult.submitPolicyFail(res);
            }
            return CommonInsureResult.submitPolicyFail(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return CommonInsureResult.submitPolicyFail();
    }

    @Override
    public CommonInsureResult cancelPolicy(CancelInsureDTO data) {
        try {
            //建立会话获取cookie
            Map<String, Object> map = getCookie();
            JSONObject json = JSONUtil.parseObj(map.get("body"));
            if (!LOGIN_SUCCESS_CODE.equals(String.valueOf(json.get("code")))) {
                log.error("登录史带接口时参数错误");
                return CommonInsureResult.cancelPolicyFail("史带保险建立会话接口错误");
            }

            //请求退保的url
            HttpHeaders headers = new HttpHeaders();
            List<String> cookie = new ArrayList<String>();
            cookie.add(map.get("cookie").toString());
            headers.put(HttpHeaders.COOKIE, cookie);
            headers.add(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
            HttpEntity<String> request = new HttpEntity<String>("", headers);
            //查询投保地址
            String submitPolicyUrl = configService.getConfigValue(CompanyEnum.STARR, PolicyConfigKeyEnum.SUBMIT_POLICY_URL);
            ResponseEntity<String> detResponse = restTemplate.exchange(submitPolicyUrl + "/" + data.getPolicyNo(), HttpMethod.DELETE, request, String.class);
            log.info("退保请求返回：{}", detResponse.getBody());
            //保存返回结果
            Order orderInfo = baseOrderMapper.selectByPolicyNo(data.getPolicyNo());
            OrderDetail orderDetail = baseOrderMapper.selectDeatailByOrderId(orderInfo.getId());
            orderDetail.setCancelPolicyRsp(detResponse.getBody());
            baseOrderMapper.updateOrderDeatailByOrderId(orderDetail);
            //查询会话URL
            String createSessionUrl = configService.getConfigValue(CompanyEnum.STARR, "createSessionUrl");
            //处理对方接口直接返回：1234数字
            if (!detResponse.getBody().contains("{")) {
                log.info("史带退保返回数据格式错误");
                //关闭会话
                ResponseEntity<String> userDelete = restTemplate.exchange(createSessionUrl, HttpMethod.DELETE, null, String.class);
                log.info("关闭会话：{}", userDelete.getBody());
                return CommonInsureResult.cancelPolicyFail("史带保险退保返回数据格式错误");
            }
            JSONObject responseJson = JSONUtil.parseObj(detResponse.getBody());
            InsureStatusEnum message;
            ResponseCode code = null;
            //文档中：只有状态为1302是退保成功
            if (CANCEL_SUCCESS_CODE.equals(String.valueOf(responseJson.get("code")))) {
                //修改数据库保单状态
                orderInfo.setStatus(OrderEnum.CANCEL.getValue());
                baseOrderMapper.updateById(orderInfo);
                message = returnMes(String.valueOf(responseJson.get("code")));
            } else {
                message = returnMes(String.valueOf(responseJson.get("code")));
            }
            //关闭会话
            ResponseEntity<String> userDelete = restTemplate.exchange(createSessionUrl, HttpMethod.DELETE, null, String.class);
            log.info("关闭会话返回：{}", userDelete.getBody());
            if (null == responseJson.get("code")) {
                return CommonInsureResult.cancelPolicyFail();
            }
            if (InsureStatusEnum.INSURE_SUCCESS.equals(message)) {
                return CommonInsureResult.cancelPolicySuccess();
            }
            return CommonInsureResult.cancelPolicyFail(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return CommonInsureResult.cancelPolicyFail();
    }

    @Override
    public CommonInsureResult downloadPolicy(DownloadInsureDTO downloadInsure) {
        try {
            //建立会话获取cookie
            Map<String, Object> map = getCookie();
            JSONObject json = JSONUtil.parseObj(map.get("body"));
            if (!LOGIN_SUCCESS_CODE.equals(String.valueOf(json.get("code")))) {
                log.error("登录史带接口时参数错误");
                return CommonInsureResult.downloadPolicyFail();
            }
            //请求下载的url
            HttpHeaders headers = new HttpHeaders();
            List<String> cookie = new ArrayList<String>();
            cookie.add(map.get("cookie").toString());
            headers.put(HttpHeaders.COOKIE, cookie);
            headers.add(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8;charset=UTF-8");
            HttpEntity<String> request = new HttpEntity<String>("", headers);
            //查询下载URL
            String downloadPolicyUrl = configService.getConfigValue(CompanyEnum.STARR, PolicyConfigKeyEnum.DOWNLOAD_POLICY_URL);
            ResponseEntity<byte[]> downResponse = restTemplate.exchange(downloadPolicyUrl + "/" + downloadInsure.getPolicyNo(), HttpMethod.GET, request, byte[].class);
            String res = new String(downResponse.getBody());
            //查询会话URL
            String createSessionUrl = configService.getConfigValue(CompanyEnum.STARR, "createSessionUrl");
            if (res.contains("false")) {
                //下载出现问题
                log.info("下载失败：{}", res);
                //关闭会话
                ResponseEntity<String> userDelete = restTemplate.exchange(createSessionUrl, HttpMethod.DELETE, null, String.class);
                log.info("关闭会话：{}", userDelete.getBody());
                return CommonInsureResult.downloadPolicyFail("下载失败：" + JSONUtil.parseObj(res).get("msg").toString());
            }
            //TODO 下载内容到本地为了测试看一下文件
//            downloadFile(downResponse.getBody());
            //关闭会话
            ResponseEntity<String> userDelete = restTemplate.exchange(createSessionUrl, HttpMethod.DELETE, null, String.class);
            log.info("关闭会话返回：{}", userDelete.getBody());
            byte[] body = downResponse.getBody();
            if (null == body || body.length == 0) {
                return CommonInsureResult.downloadPolicyFail();
            }
            return CommonInsureResult.downloadPolicySuccess(body);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return CommonInsureResult.downloadPolicyFail();
    }

    /**
     * @Description: 建立会话获取cookie
     * @Param: userInfo 用户信息
     * @Return: 响应信息
     * @Author: yws
     * @Date: 2021/3/27 10:03
     */
    private Map<String, Object> getCookie() {
        Map<String, Object> map = new HashMap<>(2);
        //查询账号密码
        String username = configService.getConfigValue(CompanyEnum.STARR, PolicyConfigKeyEnum.USERNAME);
        String password = configService.getConfigValue(CompanyEnum.STARR, PolicyConfigKeyEnum.PASSWORD);
        JSONObject jsonObject = new JSONObject();
        jsonObject.putOpt("username", username);
        jsonObject.putOpt("password", password);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
        HttpEntity<String> userRequest = new HttpEntity<String>(jsonObject.toString(), httpHeaders);
        //查询建立会话地址
        String createSessionUrl = configService.getConfigValue(CompanyEnum.STARR, "createSessionUrl");
        ResponseEntity<String> response = restTemplate.postForEntity(createSessionUrl, userRequest, String.class);
        log.info("建立会话返回：{}", response.getBody());
        map.put("body", response.getBody());
        map.put("cookie", response.getHeaders().get("Set-Cookie").get(0));
        return map;
    }


    /**
     * @Description: 返回身份证类型
     * @Param: cardType
     * @Return: String
     * @Author: yws
     * @Date: 2021/3/6 10:58
     */
    private static String getCardType(String cardType) {
        switch (cardType) {
            //身份证
            case "1":
                return "IDcard";
            //护照
            case "3":
                return "Passport";
            //组织机构代码
            case "72":
                return "OrganizaCode";
            //其他
            default:
                return "Other";
        }
    }

    /**
     * @Description: 返回信息描述
     * @Param: code 状态码
     * @Return: 信息描述
     * @Author: yws
     * @Date: 2021/3/8 13:58
     */
    private static InsureStatusEnum returnMes(String code) {
        switch (code) {
            case "1301":
                return InsureStatusEnum.INSURE_SUCCESS;
            case "1310":
                return InsureStatusEnum.INSURE_FAIL_5101;
            case "1302":
                return InsureStatusEnum.CANCEL_INSURE_SUCCESS;
            case "1030":
                return InsureStatusEnum.CANCEL_INSURE_FAIL_5201;
            case "1403":
                return InsureStatusEnum.INSURE_FAIL;
            case "1402":
                return InsureStatusEnum.CANCEL_INSURE_FAIL;
            case "1404":
                return InsureStatusEnum.INSURE_FAIL_5103;
            default:
                return InsureStatusEnum.OTHER_FAIL;
        }
    }

    /**
     * @Description: 下载内容到本地为了测试看一下文件
     * @Param: bytes 字节流
     * @Author: yws
     * @Date: 2021/3/8 15:06
     */
    private static void downloadFile(byte[] bytes) throws Exception {
        String fileName = String.valueOf(System.currentTimeMillis() / 1000) + ".pdf";
        File f = new File("D://tmp/" + fileName);
        if (!f.exists()) {
            try {
                f.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(f);
            out.write(bytes, 0, bytes.length);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        log.info("文件下载完毕：{}", f.getPath());
    }

}
